package com.kakalog.main.gpt;

import com.alibaba.fastjson2.JSON;

import lombok.Data;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class LogUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogUtil.class);

    private static final char SEPARATE_CHAT = '|';

    private static final char REPLACE_CHAT = '#';


    public static void info(String msg, Object... arguments) {
        String logText = makeLongText(msg, arguments);
        LOGGER.info(logText);
    }

    public static void debug(String msg, Object... arguments) {
        String logText = makeLongText(msg, arguments);
        LOGGER.debug(logText);
    }

    public static void warn(String msg, Object... arguments) {
        String logText = makeLongText(msg, arguments);
        LOGGER.warn(logText);
    }

    public static void warn(String msg, Throwable t, Object... arguments) {
        String logText = makeLongText(msg, arguments);
        LOGGER.warn(logText, t);
    }

    public static void error(String msg, Object... arguments) {
        String logText = makeLongText(msg, arguments);
        LOGGER.error(logText);
    }

    public static void error(String msg, Throwable t, Object... arguments) {
        String logText = makeLongText(msg, arguments);
        LOGGER.error(logText, t);
    }

    /**
     * todo 注释
     * @param msg
     * @param arguments
     * @return
     */
    private static String makeLongText(String msg, Object... arguments) {
        try {
            String className = "unknow";
            String methodName = "unknow";
            ThreadInvokeInfo threadInvokeInfo = getThreadInvokeInfo();
            if (threadInvokeInfo != null) {
                className = threadInvokeInfo.getClassSimpleName();
                methodName = threadInvokeInfo.getMethodName();
            }

            String[] argStrArray = new String[arguments.length];
            for (int i = 0; i < arguments.length; i++) {
                Object argument = arguments[i];
                if (argument instanceof String) {
                    argStrArray[i] = (String) argument;
                } else {
                    argStrArray[i] = toJSONString(argument);
                }
                argStrArray[i] = StringUtils.replaceChars(argStrArray[i], SEPARATE_CHAT, REPLACE_CHAT);
            }
            msg = msg == null ? "" : StringUtils.replaceChars(msg, SEPARATE_CHAT, REPLACE_CHAT);
            className = SEPARATE_CHAT + className;
            Object[] args = ArrayUtils.addAll(new String[] {className, methodName, msg}, argStrArray);
            return StringUtils.join(args, SEPARATE_CHAT);
        } catch (Throwable t) {
            LOGGER.error("LogUtil|makeLongText|Error occurs when making long text", t);
        }
        return "";
    }

    private static String toJSONString(Object argument) {
        if (argument == null) {
            return "";
        }
        return JSON.toJSONString(argument);
    }

    private static ThreadInvokeInfo getThreadInvokeInfo() {
        try {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

            for (StackTraceElement stackTraceElement : stackTrace) {
                if (!LogUtil.class.getName().equals(stackTraceElement.getClassName())
                    && !Thread.class.getName().equals(stackTraceElement.getClassName())) {
                    String className = stackTraceElement.getClassName();
                    className = className.substring(className.lastIndexOf(".") + 1);
                    String methodName = stackTraceElement.getMethodName();
                    return new ThreadInvokeInfo(getClassSimpleName(className), methodName);
                }
            }
            LOGGER.warn("getThreadInvokeInfo return null");
        } catch (Throwable t) {
            LOGGER.error("getThreadInvokeInfo error", t);
        }
        return null;
    }

    private static String getClassSimpleName(String fullClassName) {
        if (StringUtils.isEmpty(fullClassName)) {
            return null;
        }
        return fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
    }

    @Data
    private static class ThreadInvokeInfo {

        private String classSimpleName;

        private String methodName;

        public ThreadInvokeInfo(String classSimpleName, String method) {
            this.classSimpleName = classSimpleName;
            this.methodName = method;
        }

        public String getClassSimpleName() {
            return classSimpleName;
        }

        public String getMethodName() {
            return methodName;
        }
    }

}
